/*
 * CommonApp: version-0.0.1a
 *
 * Change Logs:
 * Date               Author              Notes
 * 2023-2-12          chenjiaxing         first version
 *
 * Description: specific application for network device, this code implements 
 *              the common operations for any device(as server in the network), used for all link type.
 */
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include "libhash.h"
#include "device_demo.h"
#include "libprotocol.h"
#include "link_socket.h"
#include "zlog.h"
int requirSetWorkMode(int devId, acqNodeWorkMode_t acqNodeWorkMode)
{
  int ret = -1;
  linkList_t *linkNode = NULL;
  linkNode = findLinkNodeFromList(gServerLinkHead, devId);
  //0. 准备payload
  acqNodeWorkMode_t setAcqNodeWorkMode;
  setAcqNodeWorkMode  = htonl(acqNodeWorkMode);
  //1. 发送命令帧
  ret = proFramesSend(&(linkNode->link.chan), (char *)&setAcqNodeWorkMode, sizeof(acqNodeWorkMode_t), \
          SPEC_OP1_SET_WORKMODE, 0, 0);
  if(ret < 0){
    zlog_error(gZlog, "failed to set workmode to device[%d], ret[%d]", devId, ret);
    return ret;
  }
  //2. 等待响应帧
  ret = waitAck(ACK_TIMEOUT_MS);
  if(ret < 0){
    zlog_error(gZlog, "set workmode to device[%d] ack timeout", devId);
    return ret;
  }
  //3. 处理接收内容
  if(/* gDevMsg.chanId != devId || */gDevMsg.op1 != SPEC_OP1_SET_WORKMODE){
    zlog_error(gZlog, "set workmode to device[%d] ack failed", devId);
    return ret;
  }
  return 0;
}

int requirGetStrain(int devId, strainInfo_t *strainInfo)
{
  int ret = -1;
  linkList_t *linkNode = NULL;
  linkNode = findLinkNodeFromList(gServerLinkHead, devId);
  //1. 发送命令帧
  ret = proFramesSend(&(linkNode->link.chan), NULL, 0, \
          SPEC_OP1_GET_STRAIN, 0, 0);
  if(ret < 0){
    zlog_error(gZlog, "failed to request strain info from device[%d], ret[%d]", devId, ret);
    return ret;
  }
  //2. 等待响应帧
  ret = waitAck(ACK_TIMEOUT_MS);
  if(ret < 0){
    zlog_error(gZlog, "request strain info from device[%d] timeout", devId);
    return ret;
  }
  //3. 处理接收内容
  if(/* gDevMsg.chanId != devId || */gDevMsg.op1 != SPEC_OP1_GET_STRAIN){
    zlog_error(gZlog, "recv strain info from device[%d] ack failed", devId);
    return ret;
  }
  strainInfo_t getStrainInfo;
  memcpy(&getStrainInfo, gDevMsg.payload, sizeof(strainInfo_t));
  strainInfo->devId             = gDevMsg.op2;
  strainInfo->timeStamp.tv_sec  = ntohl(getStrainInfo.timeStamp.tv_sec);
  strainInfo->timeStamp.tv_usec = ntohl(getStrainInfo.timeStamp.tv_usec);
  strainInfo->strainVal         = ntohl(getStrainInfo.strainVal);
  //4. print info
  struct tm fmtTime = {0};
  localtime_r(&(strainInfo->timeStamp.tv_sec), &fmtTime);
  char timeStampStr[32] = {0};
  strftime(timeStampStr, sizeof(timeStampStr), "%Y-%m-%d %H:%M:%S", &fmtTime);
  sprintf(&timeStampStr[19], ".%ld", strainInfo->timeStamp.tv_usec / 1000);
  zlog_info(gZlog, "\nrecv strain acqNode[%d] data:\
      time stamp.........[%s] \
      strain value.......[%.4f]", \
      strainInfo->devId, timeStampStr, strainInfo->strainVal);
  return 0;
}

int testStrain(int devId)
{
  int ret = -1;
  linkList_t *linkNode = NULL;
  linkNode = findLinkNodeFromList(gServerLinkHead, devId);
  //1. data prepare
  strainInfo_t strainInfo;
  struct timeval now;
  gettimeofday(&now, NULL);
  struct tm fmtTime = {0};
  localtime_r(&(now.tv_sec), &fmtTime);
  char timeStampStr[32] = {0};
  strftime(timeStampStr, sizeof(timeStampStr), "%Y-%m-%d %H:%M:%S", &fmtTime);
  sprintf(&timeStampStr[19], ".%ld", strainInfo.timeStamp.tv_usec / 1000);
  strainInfo.devId             = 1;
  strainInfo.strainVal         = 3.14;
  zlog_info(gZlog, "\nrecv strain acqNode[%d] data:\
      time stamp.........[%s] \
      strain value.......[%.4f]", \
      strainInfo.devId, timeStampStr, strainInfo.strainVal);
  // 2. htoh
  strainInfo.timeStamp.tv_sec  = htonl(now.tv_sec);
  strainInfo.timeStamp.tv_usec = htonl(now.tv_usec);
  strainInfo.strainVal         = htonl(strainInfo.strainVal);
  //3. 发送命令帧
  ret = proFramesSend(&(linkNode->link.chan), (char *)&strainInfo, sizeof(strainInfo_t), \
          SPEC_OP1_GET_STRAIN, 0, 0);
  if(ret < 0){
    zlog_error(gZlog, "failed to request strain info from device[%d], ret[%d]", devId, ret);
    return ret;
  }
  
  return 0;
}

int requirGetVibration(int devId, vibrationInfo_t *vibrationInfo)
{
  int ret = -1;
  linkList_t *linkNode = NULL;
  linkNode = findLinkNodeFromList(gServerLinkHead, devId);
  //1. 发送命令帧
  ret = proFramesSend(&(linkNode->link.chan), NULL, 0, \
          SPEC_OP1_GET_VIBRATION, 0, 0);
  if(ret < 0){
    zlog_error(gZlog, "failed to request vibration info from device[%d], ret[%d]", devId, ret);
    return ret;
  }
  //2. 等待响应帧
  ret = waitAck(ACK_TIMEOUT_MS);
  if(ret < 0){
    zlog_error(gZlog, "request vibration info from device[%d] timeout", devId);
    return ret;
  }
  //3. 处理接收内容
  if(/* gDevMsg.chanId != devId || */gDevMsg.op1 != SPEC_OP1_GET_VIBRATION){
    zlog_error(gZlog, "recv vibration info from device[%d] ack failed", devId);
    return ret;
  }
  vibrationInfo_t getVibrationInfo;
  memcpy(&getVibrationInfo, gDevMsg.payload, sizeof(vibrationInfo_t));
  vibrationInfo->devId          = gDevMsg.op1;
  vibrationInfo->timeStamp.tv_sec  = ntohl(getVibrationInfo.timeStamp.tv_sec);
  vibrationInfo->timeStamp.tv_usec = ntohl(getVibrationInfo.timeStamp.tv_usec);
  vibrationInfo->accSpeedX         = ntohl(getVibrationInfo.accSpeedX);
  vibrationInfo->accSpeedY         = ntohl(getVibrationInfo.accSpeedY);
  vibrationInfo->accSpeedZ         = ntohl(getVibrationInfo.accSpeedZ);
  vibrationInfo->angleX            = ntohl(getVibrationInfo.angleX);
  vibrationInfo->angleY            = ntohl(getVibrationInfo.angleY);
  vibrationInfo->angleZ            = ntohl(getVibrationInfo.angleZ);
  //4. print info
  struct tm fmtTime = {0};
  localtime_r(&(vibrationInfo->timeStamp.tv_sec), &fmtTime);
  char timeStampStr[32] = {0};
  strftime(timeStampStr, sizeof(timeStampStr), "%Y-%m-%d %H:%M:%S", &fmtTime);
  sprintf(&timeStampStr[19], ".%ld", vibrationInfo->timeStamp.tv_usec / 1000);
  zlog_info(gZlog, "\nrecv vibration acqNode[%d] data:\
      time stamp.........[%s] \
      accSpeedX value....[%.4f] \
      accSpeedY value....[%.4f] \
      accSpeedZ value....[%.4f] \
      angleX value.......[%.4f] \
      angleY value.......[%.4f] \
      angleZ value.......[%.4f]", \
      vibrationInfo->devId, timeStampStr, vibrationInfo->accSpeedX, \
      vibrationInfo->accSpeedY, vibrationInfo->accSpeedZ, \
      vibrationInfo->angleX, vibrationInfo->angleY, vibrationInfo->angleZ);
  return 0;
}

int testVibration(int devId)
{
  int ret = -1;
  linkList_t *linkNode = NULL;
  linkNode = findLinkNodeFromList(gServerLinkHead, devId);
  //1. data prepare
  vibrationInfo_t vibrationInfo;
  struct timeval now;
  gettimeofday(&now, NULL);
  struct tm fmtTime = {0};
  localtime_r(&(now.tv_sec), &fmtTime);
  char timeStampStr[32] = {0};
  strftime(timeStampStr, sizeof(timeStampStr), "%Y-%m-%d %H:%M:%S", &fmtTime);
  sprintf(&timeStampStr[19], ".%ld", now.tv_usec / 1000);
  vibrationInfo.devId             = 1;
  vibrationInfo.accSpeedX         = 3.11;
  vibrationInfo.accSpeedY         = 3.12;
  vibrationInfo.accSpeedZ         = 3.13;
  vibrationInfo.angleX            = 3.14;
  vibrationInfo.angleY            = 3.15;
  vibrationInfo.angleZ            = 3.16;
  zlog_info(gZlog, "\nrecv vibration acqNode[%d] data:\
      time stamp............[%s] \
      accSpeedX value.......[%.4f]\
      accSpeedY value.......[%.4f]\
      accSpeedZ value.......[%.4f]\
      angleX value..........[%.4f]\
      angleY value..........[%.4f]\
      angleZ value..........[%.4f]", \
      vibrationInfo.devId, timeStampStr, \
      vibrationInfo.accSpeedX, vibrationInfo.accSpeedY, \
      vibrationInfo.accSpeedZ, vibrationInfo.angleX, \
      vibrationInfo.angleY, vibrationInfo.angleZ);
  // 2. htoh
  vibrationInfo.timeStamp.tv_sec      = htonl(now.tv_sec);
  vibrationInfo.timeStamp.tv_usec     = htonl(now.tv_usec);
  vibrationInfo.accSpeedX             = htonl(vibrationInfo.accSpeedX);
  vibrationInfo.accSpeedY             = htonl(vibrationInfo.accSpeedY);
  vibrationInfo.accSpeedZ             = htonl(vibrationInfo.accSpeedZ);
  vibrationInfo.angleX                = htonl(vibrationInfo.angleX);
  vibrationInfo.angleY                = htonl(vibrationInfo.angleY);
  vibrationInfo.angleZ                = htonl(vibrationInfo.angleZ);
  //3. 发送命令帧
  ret = proFramesSend(&(linkNode->link.chan), (char *)&vibrationInfo, sizeof(vibrationInfo_t), \
          SPEC_OP1_GET_VIBRATION, 0, 0);
  if(ret < 0){
    zlog_error(gZlog, "failed to request vibration info from device[%d], ret[%d]", devId, ret);
    return ret;
  }
  
  return 0;
}

int devCommPth(int devNumCfg)
{
  int ret = -1;
  int devCntFind = 0;
  linkList_t *crtLink = NULL;
  
  strainInfo_t strainInfo = {0};
  vibrationInfo_t vibrationInfo = {0};
  zlog_info(gZlog, "\n[%d] acqNodes config to the system", devNumCfg);
  while(1){// main loop
    devCntFind = sizeOfLinkList(gServerLinkHead);
    if(devCntFind == 0){
      zlog_error(gZlog, "except [%d] acqNodes but [%d] acqNodes are found", devNumCfg, devCntFind);
    }else if(devCntFind != devNumCfg){
      zlog_error(gZlog, "except [%d] acqNodes but [%d] acqNodes are found", devNumCfg, devCntFind);
    }

    for(int i = 1; i <= 18; i++){
    crtLink = findLinkNodeFromList(gServerLinkHead, i);
      if(crtLink){
        zlog_debug(gZlog, "find devId[%d]", crtLink->link.linkId);
        ret = requirGetVibration(i, &vibrationInfo);
        //ret = requirGetStrain(i, &strainInfo);
        //ret = testStrain(i);
        //ret = testVibration(i);
      }
    }
    //usleep(10000000);
  }
  return ret;
}

int devCommPthInit(int devNum)
{
  pthread_t commPth;
    if (pthread_create(&commPth, NULL, (void *)devCommPth, devNum) != 0){
        zlog_error(gZlog, "Failed to create devCommPth");
        return -1;
    }
    pthread_detach(commPth);
    return 0;
}
